<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>私有攻略库问答（Vue + Axios）</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    * { box-sizing: border-box; }
    body { margin: 0; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif; background: #f6f7fb; color: #222; }
    .container { max-width: 920px; margin: 24px auto; padding: 0 16px; }
    .card { background: #fff; border-radius: 12px; box-shadow: 0 6px 16px rgba(0,0,0,.06); padding: 20px; margin-bottom: 16px; }
    .title { font-size: 20px; font-weight: 700; margin: 0 0 12px; }
    label { display: block; font-size: 13px; color: #666; margin-bottom: 6px; }
    textarea, input[type="number"], input[type="text"] { width: 100%; padding: 12px 12px; border: 1px solid #e6e6e6; border-radius: 10px; outline: none; font-size: 14px; background: #fcfcfd; }
    textarea:focus, input:focus { border-color: #6a7cff; box-shadow: 0 0 0 3px rgba(106,124,255,.12); }
    .row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
    .row .col { flex: 1; min-width: 180px; }
    .btn { appearance: none; border: none; cursor: pointer; border-radius: 10px; padding: 10px 16px; font-size: 14px; font-weight: 600; color: #fff; background: linear-gradient(135deg, #6a7cff, #4c63f7); box-shadow: 0 6px 14px rgba(76,99,247,.3); }
    .btn:disabled { opacity: .6; cursor: not-allowed; }
    .answer { white-space: pre-wrap; line-height: 1.7; border-radius: 10px; background: #fafafe; border: 1px solid #eee; padding: 16px; }
    .muted { color: #888; font-size: 13px; }
    .error { color: #d23c3c; background: #fff3f3; border: 1px solid #ffd8d8; padding: 10px 12px; border-radius: 8px; }
    .note { border: 1px solid #eee; border-radius: 10px; padding: 12px; background: #fff; }
    .note-id { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; color: #666; font-size: 12px; }
    .note-title { font-weight: 700; margin: 4px 0 6px; }
    .footer-tip { text-align: center; color: #999; font-size: 12px; margin-top: 24px; }
    .loading { display: inline-flex; align-items: center; gap: 8px; color: #4c63f7; }
    .dot { width: 8px; height: 8px; background: #4c63f7; border-radius: 50%; animation: b .9s infinite ease-in-out; }
    .dot:nth-child(2) { animation-delay: .15s; }
    .dot:nth-child(3) { animation-delay: .3s; }
    @keyframes b { 0%,80%,100%{ transform: scale(0); } 40%{ transform: scale(1); } }
    .kbd { display: inline-block; border: 1px solid #ddd; border-bottom-width: 2px; padding: 0 6px; border-radius: 6px; font-size: 12px; background: #f8f8fa; }
    .link { color: #4c63f7; text-decoration: none; }

        .footer-container {
            padding-bottom: 20px;
            background-color: #3c3c3c;
            font-size: 12px;
            color: #c2c2c2;
            .footer-wrap {
                width: 1105px;
                margin: 0 auto;
                .footer-info {
                    padding: 30px 8px 40px 8px;
                    border-bottom: 1px solid #575a5b;
                    .footer-info-intro {
                        display: inline-block;
                        vertical-align: top;
                        width: 200px;
                        line-height: 22px;
                        margin-right: 68px;
                    }
                    .footer-info-about {
                        display: inline-block;
                        vertical-align: top;
                        width: 128px;
                        line-height: 22px;
                        margin-right: 85px;
                        a {
                            background-color: transparent;
                            text-decoration: none;
                            color: #c2c2c2;
                            cursor: pointer;
                            &:hover {
                                color: #fff;
                                text-decoration: none;
                            }
                        }
                    }
                    .footer-info-service {
                        display: inline-block;
                        vertical-align: top;
                        width: 135px;
                        line-height: 22px;
                        margin-right: 80px;
                        h4 {
                            text-align: center;
                        }
                        .service-item {
                            display: flex;
                            justify-content: space-between;
                        }
                        a {
                            background-color: transparent;
                            text-decoration: none;
                            color: #c2c2c2;
                            cursor: pointer;
                            &:hover {
                                color: #fff;
                                text-decoration: none;
                            }
                        }
                    }
                    .footer-info-qrcode {
                        display: inline-block;
                        padding-top: 22px;
                        .qrcode-item {
                            display: inline-block;
                            margin-left: 30px;
                            vertical-align: top;
                            .qrcode-info {
                                text-align: center;
                                font-size: 12px;
                            }
                        }
                    }
                    .footer-info-social {
                        padding-top: 25px;
                        text-align: center;
                        .social-title {
                            height: 30px;
                            font-size: 16px;
                            overflow: hidden;
                        }
                        .footer-social-weibo {
                            display: inline-block;
                            margin: 0 6px;
                            .ft-social-icon {
                                display: inline-block;
                                width: 28px;
                                height: 28px;
                                background: url(../assets/images/mfw-footer-sprite7.png) no-repeat 0 0;
                                overflow: hidden;
                            }
                        }
                        .footer-social-qzone {
                            display: inline-block;
                            margin: 0 6px;
                            .ft-social-icon {
                                display: inline-block;
                                width: 28px;
                                height: 28px;
                                background: url(../assets/images/mfw-footer-sprite7.png) no-repeat 0 0;
                                background-position: -60px 0;
                                overflow: hidden;
                            }
                        }
                    }
                    h4 {
                        margin: 0px;
                        padding-bottom: 10px;
                        font-size: 14px;
                        overflow: hidden;
                    }
                    .m_l_10 {
                        margin-left: 10px;
                    }
                }
                .footer-links {
                    padding: 17px 0 0px 8px;
                    line-height: 22px;
                    border-top: 1px solid #575a5b;
                    a {
                        display: inline-block;
                        margin-right: 12px;
                        color: #c2c2c2;
                        &:hover {
                            outline: 0;
                            text-decoration: underline;
                        }
                    }
                }
            }
        }
    </style>

</head>
<body>
<div style="width: 100%; height: 600px;">
    <img height="600" width="100%" src="https://p1-q.mafengwo.net/s15/M00/0F/5F/CoUBGV28HDuALpzxABR490kDN0M39.jpeg" />
</div>
  <div id="app" class="container">
    <div class="card">
      <h2 class="title">站内资源AI智能推荐</h2>
      <div class="row" style="margin-bottom: 10px;">
        <div class="col">
          <label>请输入关键字</label>
          <textarea v-model.trim="question" rows="1" ></textarea>
        </div>
          <div class="col" style="flex: 0; display: flex; gap: 8px;">
              <div>
                  <label>&nbsp;</label>
                  <button class="btn" :disabled="disabledAsk" @click="ask">
                      {{ loading ? '请求中...' : '发送提问' }}
                  </button>
              </div>
              <div>
                  <label>&nbsp;</label>
                  <button class="btn" style="background: #29a36a;" :disabled="loading" @click="ping" hidden="hidden">
                      测试连接
                  </button>
              </div>
          </div>
      </div>

      <div class="row" style="margin-bottom: 14px;">
<!--          <div class="col" style="flex: 0; display: flex; gap: 8px;">-->
<!--              <div>-->
<!--                  <label>&nbsp;</label>-->
<!--                  <button class="btn" :disabled="disabledAsk" @click="ask">-->
<!--                      {{ loading ? '请求中...' : '发送提问' }}-->
<!--                  </button>-->
<!--              </div>-->
<!--              <div>-->
<!--                  <label>&nbsp;</label>-->
<!--                  <button class="btn" style="background: #29a36a;" :disabled="loading" @click="ping" hidden="hidden">-->
<!--                      测试连接-->
<!--                  </button>-->
<!--              </div>-->
<!--          </div>-->
        <div class="col" style="max-width: 160px;">
<!--          <label>topK（检索条数 1-10）</label>-->
          <input type="number" v-model.number="topK" min="1" max="10" hidden="hidden" />
        </div>
        <div class="col" style="max-width: 360px;">
<!--          <label>接口地址（为空时自动推断）</label>-->
          <input type="text" v-model.trim="apiBase" placeholder="例如：http://localhost:8080" hidden="hidden" />
        </div>

      </div>

    </div>

    <div class="card">
      <h3 class="title" style="margin-bottom: 10px;">AI推荐</h3>

      <div v-if="error" class="error" style="margin-bottom: 12px;">{{ error }}</div>

      <div v-if="loading" class="loading" style="margin-bottom: 12px;">
        <span class="dot"></span><span class="dot"></span><span class="dot"></span> 正在生成回答...
      </div>

      <div v-if="!loading && answer" class="answer">{{ answer }}</div>
      <div v-else-if="!loading" class="muted">暂无回答</div>
    </div>

    <div class="card">
      <h3 class="title" style="margin-bottom: 10px;">站内旅行攻略</h3>
              <div v-if="strategies && strategies.length">
          <div v-for="n in strategies" :key="n.id" class="note" style="margin-bottom: 10px;">
          <div class="note-id">ID: {{ n.id }}</div>
          <div class="note-title">{{ n.title }}</div>
          <div v-if="n.subTitle" class="muted" style="font-style: italic; color: #666;">{{ n.subTitle }}</div>
          <div class="muted">{{ n.summary }}</div>
        </div>
      </div>
      <div v-else class="muted">本次回答未引用私有攻略或结果为空</div>
    </div>

    <div class="footer-tip">
      如需录入数据，请调用 <code>POST /strategies</code> 接口。按 <span class="kbd">Ctrl</span> + <span class="kbd">Enter</span> 快速提交。
    </div>
  </div>

  <div class="footer-container">
      <div class="footer-wrap">
          <div class="footer-info">
              <div class="footer-info-intro">
                  <h4>带TA游旅游网</h4>
                  <p>中国年轻一代用得更多的旅游网站</p>
                  <p>上亿旅行者共同打造的"旅行神器"</p>
                  <p>60,000 多个全球旅游目的地</p>
                  <p>600,000 个细分目的地新玩法</p>
                  <p>760,000,000 次攻略下载</p>
                  <p>38,000 家旅游产品供应商</p>
              </div>
              <div class="footer-info-about">
                  <h4>关于我们</h4>
                  <p>
                      <a href="/" rel="nofollow">关于带TA游</a>
                      <a href="/" class="m_l_10" rel="nofollow">联系我们</a>
                  </p>
                  <p>
                      <a href="/" rel="nofollow">隐私政策</a>
                      <a href="/" rel="nofollow" class="m_l_10">商标声明</a>
                  </p>
                  <p><a href="/" rel="nofollow">服务协议</a></p>
                  <p><a href="/" rel="nofollow">商城平台服务协议</a></p>
              </div>
              <div class="footer-info-service">
                  <h4>旅行服务</h4>
                  <p class="service-item">
                      <a target="_blank" href="/strategy">旅游攻略</a>
                      <a target="_blank" href="/hotel">酒店预订</a>
                  </p>
                  <p class="service-item">
                      <a target="_blank" href="/strategy">旅游攻略</a>
                      <a target="_blank" href="/hotel">酒店预订</a>
                  </p>
                  <p class="service-item">
                      <a target="_blank" href="/strategy">旅游攻略</a>
                      <a target="_blank" href="/hotel">酒店预订</a>
                  </p>
                  <p class="service-item">
                      <a target="_blank" href="/strategy">旅游攻略</a>
                      <a target="_blank" href="/hotel">酒店预订</a>
                  </p>
              </div>
              <div class="footer-info-qrcode">
                  <div class="qrcode-item">
                      <el-image
                              style="width: 100px; height: 100px"
                              src="https://p3-q.mafengwo.net/s10/M00/48/A9/wKgBZ1t_4sSAVJ6uAAAlzJ0PZgU881.png?imageMogr2%2Fthumbnail%2F%2194x90r%2Fgravity%2FCenter%2Fcrop%2F%2194x90%2Fquality%2F90"
                      />
                      <p class="qrcode-info">带TA游APP<br />扫描立即下载</p>
                  </div>
                  <div class="qrcode-item">
                      <el-image
                              style="width: 100px; height: 100px"
                              src="https://p3-q.mafengwo.net/s10/M00/48/A9/wKgBZ1t_4sSAVJ6uAAAlzJ0PZgU881.png?imageMogr2%2Fthumbnail%2F%2194x90r%2Fgravity%2FCenter%2Fcrop%2F%2194x90%2Fquality%2F90"
                      />
                      <p class="qrcode-info">带TA游旅游<br />订阅号</p>
                  </div>
                  <div class="qrcode-item">
                      <el-image
                              style="width: 100px; height: 100px"
                              src="https://p3-q.mafengwo.net/s10/M00/48/A9/wKgBZ1t_4sSAVJ6uAAAlzJ0PZgU881.png?imageMogr2%2Fthumbnail%2F%2194x90r%2Fgravity%2FCenter%2Fcrop%2F%2194x90%2Fquality%2F90"
                      />
                      <p class="qrcode-info">带TA游良品<br />官方服务号</p>
                  </div>
              </div>
              <div class="footer-info-social">
                  <h4 class="social-title">旅游之前，先上带TA游！</h4>
                  <a class="footer-social-weibo" target="_blank" href="http://weibo.com/mafengwovip" rel="nofollow">
                      <i class="ft-social-icon" />
                  </a>
                  <a class="footer-social-qzone" target="_blank" href="http://1213600479.qzone.qq.com/" rel="nofollow">
                      <i class="ft-social-icon" />
                  </a>
              </div>
          </div>
          <div class="footer-links">
              <a target="_blank" href="http://china.makepolo.com/">马可波罗</a>
              <a target="_blank" href="http://www.onlylady.com/">Onlylady女人志</a>
              <a target="_blank" href="http://trip.elong.com/">艺龙旅游指南</a>
              <a target="_blank" href="http://www.cncn.com">欣欣旅游网</a>
              <a target="_blank" href="http://www.8264.com/">户外运动</a>
              <a target="_blank" href="http://www.yue365.com/">365音乐网</a>
              <a target="_blank" href="http://ishare.iask.sina.com.cn/">爱问共享资料</a>
              <a target="_blank" href="http://www.uzai.com/">旅游网</a>
              <a target="_blank" href="http://www.zongheng.com/">小说网</a>
              <a target="_blank" href="http://www.xuexila.com/">学习啦</a>
              <a target="_blank" href="http://www.yododo.com">游多多自助游</a>
              <a target="_blank" href="http://www.zhcpic.com/">问答</a>
              <a target="_blank" href="http://huoche.mafengwo.cn/">火车时刻表</a>
              <a target="_blank" href="http://www.lvmama.com">驴妈妈旅游网</a>
              <a target="_blank" href="http://www.haodou.com/">好豆美食网</a>
              <a target="_blank" href="http://www.taoche.com/">二手车</a>
              <a target="_blank" href="http://www.lvye.cn">绿野户外</a>
              <a target="_blank" href="http://www.tuniu.com/">途牛旅游网</a>
              <a target="_blank" href="http://www.mapbar.com/">图吧</a>
              <a target="_blank" href="http://www.chnsuv.com">SUV联合越野</a>
              <a target="_blank" href="http://www.uc.cn/">手机浏览器</a>
              <a target="_blank" href="http://sh.city8.com/">上海地图</a>
              <a target="_blank" href="http://www.tianqi.com/">天气预报查询</a>
              <a target="_blank" href="http://www.ly.com/">同程旅游</a>
              <a target="_blank" href="http://www.tieyou.com/">火车票</a>
              <a target="_blank" href="http://www.yunos.com/">YunOS</a>
              <a target="_blank" href="http://you.ctrip.com/">携程旅游</a>
              <a target="_blank" href="http://www.jinjiang.com">锦江旅游</a>
              <a target="_blank" href="http://www.huoche.net/">火车时刻表</a>
              <a target="_blank" href="http://www.tripadvisor.cn/">TripAdvisor</a>
              <a target="_blank" href="http://www.tianxun.com/">天巡网</a>
              <a target="_blank" href="http://www.mayi.com/">短租房</a>
              <a target="_blank" href="http://www.zuzuche.com">租租车</a>
              <a target="_blank" href="http://www.5fen.com/">五分旅游网</a>
              <a target="_blank" href="http://www.zhuna.cn/">酒店预订</a>
              <a target="_blank" href="http://www.ailvxing.com">爱旅行网</a>
              <a target="_blank" href="http://360.mafengwo.cn/all.php">旅游</a>
              <a target="_blank" href="http://vacations.ctrip.com/">旅游网</a>
              <a target="_blank" href="http://www.wed114.cn">wed114结婚网</a>
              <a target="_blank" href="http://www.chexun.com/">车讯网</a>
              <a target="_blank" href="http://www.aoyou.com/">遨游旅游网</a>
              <a target="_blank" href="http://www.91.com/">手机</a>
              <a href="javascript:;" target="_blank">更多友情链接&gt;&gt;</a>
          </div>
      </div>
  </div>

  <script setup lang="ts"></script>


<!--  <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.global.min.js"></script>-->
<!--  <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.min.js"></script>-->
<script src="/js/vue.global.min.js"></script>
<script src="/js/axios.min.js"></script>
  <script>
    // 捕获未处理的 Promise 错误，避免浏览器扩展引起的噪音报错
    window.addEventListener('unhandledrejection', function (event) {
      if (event && event.reason && /Receiving end does not exist/i.test(String(event.reason))) {
        event.preventDefault();
      }
    });

    const app = Vue.createApp({
      data() {
        return {
          question: '',
          topK: 3,
          apiBase: '',
          answer: '',
          strategies: [],
          loading: false,
          error: ''
        }
      },
      computed: {
        disabledAsk() {
          return this.loading || !this.question || this.topK < 1 || this.topK > 10;
        },
        baseURL() {
          if (this.apiBase && this.apiBase.trim()) return this.apiBase.trim().replace(/\/$/, '');
          if (location.protocol === 'file:') return 'http://localhost:8080';
          return window.location.origin;
        }
      },
      methods: {
        async ask() {
          if (this.disabledAsk) return;
          this.loading = true;
          this.error = '';
          this.answer = '';
          this.strategies = [];
          try {
            const resp = await axios.post(this.baseURL + '/chat', { question: this.question, topK: this.topK }, {
              headers: { 'Content-Type': 'application/json' },
              timeout: 60000,
              withCredentials: false
            });
            this.answer = resp?.data?.answer || '(无回答)';
            this.strategies = Array.isArray(resp?.data?.strategies) ? resp.data.strategies : [];
          } catch (e) {
            this.error = this.formatError(e);
          } finally {
            this.loading = false;
          }
        },
        async ping() {
          this.error = '';
          try {
            await axios.get(this.baseURL + '/__ping__', { timeout: 5000 }).catch(() => {});
            await axios({ method: 'OPTIONS', url: this.baseURL + '/strategies', timeout: 5000 }).catch(() => {});
            alert('与后端通信正常（或已通过 CORS 预检）。');
          } catch (e) {
            alert('连接失败：' + this.formatError(e));
          }
        },
        formatError(e) {
          const status = e?.response?.status;
          if (status === 0) return '网络不可达，请检查接口地址或代理设置。';
          const msg = e?.response?.data?.message || e?.message || '请求失败';
          if (status) return `HTTP ${status}: ${msg}`;
          return msg;
        }
      },
      mounted() {
        window.addEventListener('keydown', (ev) => {
          if (ev.ctrlKey && ev.key === 'Enter') this.ask();
        });
      }
    });
    app.mount('#app');
  </script>
</body>
</html>



